#!/bin/bash
"""
网络安全漏洞知识图谱项目测试执行脚本
支持不同类型的测试和测试环境管理
"""

set -e  # 遇到错误立即退出

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# 日志函数
log_info() {
    echo -e "${BLUE}[INFO]${NC} $1"
}

log_success() {
    echo -e "${GREEN}[SUCCESS]${NC} $1"
}

log_warning() {
    echo -e "${YELLOW}[WARNING]${NC} $1"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

# 显示帮助信息
show_help() {
    cat << EOF
网络安全漏洞知识图谱项目测试脚本

用法: $0 [选项] [测试类型]

测试类型:
    unit            运行单元测试
    integration     运行集成测试
    e2e             运行端到端测试
    performance     运行性能测试
    security        运行安全测试
    all             运行所有测试 (默认)
    quick           快速测试 (仅单元测试)

选项:
    -h, --help      显示帮助信息
    -v, --verbose   详细输出
    -c, --coverage  生成测试覆盖率报告
    -r, --report    生成HTML测试报告
    -p, --parallel  并行执行测试
    -f, --failfast  遇到第一个失败就停止
    -k PATTERN      只运行匹配模式的测试
    -m MARKERS      只运行带有指定标记的测试
    --setup         只设置测试环境
    --cleanup       只清理测试环境
    --no-docker     不使用Docker测试环境

示例:
    $0 unit -c              # 运行单元测试并生成覆盖率报告
    $0 all -v -r            # 运行所有测试，详细输出，生成HTML报告
    $0 performance          # 运行性能测试
    $0 -k "test_crawler"    # 只运行包含"test_crawler"的测试

EOF
}

# 默认参数
TEST_TYPE="all"
VERBOSE=""
COVERAGE=""
HTML_REPORT=""
PARALLEL=""
FAILFAST=""
PATTERN=""
MARKERS=""
SETUP_ONLY=""
CLEANUP_ONLY=""
USE_DOCKER="true"

# 解析命令行参数
while [[ $# -gt 0 ]]; do
    case $1 in
        -h|--help)
            show_help
            exit 0
            ;;
        -v|--verbose)
            VERBOSE="-v"
            shift
            ;;
        -c|--coverage)
            COVERAGE="--cov=src --cov-report=html --cov-report=xml --cov-report=term"
            shift
            ;;
        -r|--report)
            HTML_REPORT="--html=tests/reports/test_report.html --self-contained-html"
            shift
            ;;
        -p|--parallel)
            PARALLEL="-n auto"
            shift
            ;;
        -f|--failfast)
            FAILFAST="--maxfail=1"
            shift
            ;;
        -k)
            PATTERN="-k $2"
            shift 2
            ;;
        -m)
            MARKERS="-m $2"
            shift 2
            ;;
        --setup)
            SETUP_ONLY="true"
            shift
            ;;
        --cleanup)
            CLEANUP_ONLY="true"
            shift
            ;;
        --no-docker)
            USE_DOCKER="false"
            shift
            ;;
        unit|integration|e2e|performance|security|all|quick)
            TEST_TYPE="$1"
            shift
            ;;
        *)
            log_error "未知参数: $1"
            show_help
            exit 1
            ;;
    esac
done

# 获取脚本目录
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
cd "$PROJECT_ROOT"

# 创建报告目录
mkdir -p tests/reports

# 检查Python环境
check_python_env() {
    log_info "检查Python环境..."
    
    if ! command -v python3 &> /dev/null; then
        log_error "Python3 未找到，请先安装Python 3.11+"
        exit 1
    fi
    
    python_version=$(python3 -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')")
    if [[ $(echo "$python_version >= 3.11" | bc -l) -eq 0 ]]; then
        log_warning "建议使用Python 3.11+，当前版本: $python_version"
    fi
    
    log_success "Python环境检查通过"
}

# 安装测试依赖
install_test_dependencies() {
    log_info "安装测试依赖..."
    
    if [ ! -f "tests/requirements.txt" ]; then
        log_error "tests/requirements.txt 未找到"
        exit 1
    fi
    
    pip install -r tests/requirements.txt
    pip install -r requirements.txt
    
    log_success "测试依赖安装完成"
}

# 设置测试环境
setup_test_environment() {
    log_info "设置测试环境..."
    
    # 创建必要目录
    mkdir -p tests/{data,reports,logs}
    mkdir -p tests/data/{raw,processed,expected,mock_apis}
    
    # 生成测试数据
    if [ -f "tests/data/generate_test_data.py" ]; then
        log_info "生成测试数据..."
        python tests/data/generate_test_data.py
    fi
    
    if [ "$USE_DOCKER" = "true" ]; then
        # 启动Docker测试环境
        log_info "启动Docker测试环境..."
        
        if command -v docker-compose &> /dev/null; then
            docker-compose -f tests/docker-compose.test.yml up -d
            
            # 等待服务启动
            log_info "等待测试服务启动..."
            sleep 30
            
            # 检查服务状态
            check_test_services
        else
            log_warning "Docker Compose 未找到，使用本地服务"
        fi
    fi
    
    log_success "测试环境设置完成"
}

# 检查测试服务状态
check_test_services() {
    log_info "检查测试服务状态..."
    
    services=("redis-test:6380" "mongodb-test:27018" "neo4j-test:7475")
    
    for service in "${services[@]}"; do
        service_name=$(echo $service | cut -d: -f1)
        port=$(echo $service | cut -d: -f2)
        
        if ! nc -z localhost $port; then
            log_warning "服务 $service_name 未就绪"
        else
            log_success "服务 $service_name 已就绪"
        fi
    done
}

# 清理测试环境
cleanup_test_environment() {
    log_info "清理测试环境..."
    
    if [ "$USE_DOCKER" = "true" ] && command -v docker-compose &> /dev/null; then
        docker-compose -f tests/docker-compose.test.yml down -v
    fi
    
    # 清理临时文件
    find tests/ -name "*.pyc" -delete
    find tests/ -name "__pycache__" -type d -exec rm -rf {} + 2>/dev/null || true
    find tests/ -name ".pytest_cache" -type d -exec rm -rf {} + 2>/dev/null || true
    
    log_success "测试环境清理完成"
}

# 运行代码质量检查
run_code_quality_checks() {
    log_info "运行代码质量检查..."
    
    # 代码格式检查
    if command -v black &> /dev/null; then
        log_info "检查代码格式..."
        black --check src/ tests/ || log_warning "代码格式检查失败"
    fi
    
    # 导入排序检查
    if command -v isort &> /dev/null; then
        log_info "检查导入排序..."
        isort --check-only src/ tests/ || log_warning "导入排序检查失败"
    fi
    
    # 静态类型检查
    if command -v mypy &> /dev/null; then
        log_info "运行静态类型检查..."
        mypy src/ || log_warning "类型检查发现问题"
    fi
    
    # 代码风格检查
    if command -v flake8 &> /dev/null; then
        log_info "检查代码风格..."
        flake8 src/ tests/ || log_warning "代码风格检查发现问题"
    fi
    
    log_success "代码质量检查完成"
}

# 运行单元测试
run_unit_tests() {
    log_info "运行单元测试..."
    
    pytest tests/unit/ \
        $VERBOSE \
        $COVERAGE \
        $HTML_REPORT \
        $PARALLEL \
        $FAILFAST \
        $PATTERN \
        $MARKERS \
        --junit-xml=tests/reports/unit_test_results.xml \
        --timeout=60
    
    log_success "单元测试完成"
}

# 运行集成测试
run_integration_tests() {
    log_info "运行集成测试..."
    
    pytest tests/integration/ \
        $VERBOSE \
        $COVERAGE \
        $HTML_REPORT \
        $FAILFAST \
        $PATTERN \
        $MARKERS \
        --junit-xml=tests/reports/integration_test_results.xml \
        --timeout=120
    
    log_success "集成测试完成"
}

# 运行端到端测试
run_e2e_tests() {
    log_info "运行端到端测试..."
    
    pytest tests/e2e/ \
        $VERBOSE \
        $COVERAGE \
        $HTML_REPORT \
        $FAILFAST \
        $PATTERN \
        $MARKERS \
        --junit-xml=tests/reports/e2e_test_results.xml \
        --timeout=300
    
    log_success "端到端测试完成"
}

# 运行性能测试
run_performance_tests() {
    log_info "运行性能测试..."
    
    # Pytest性能测试
    pytest tests/performance/ \
        $VERBOSE \
        $PATTERN \
        $MARKERS \
        --benchmark-json=tests/reports/benchmark_results.json \
        --timeout=600
    
    # Locust负载测试
    if [ -f "tests/performance/locustfile.py" ]; then
        log_info "运行Locust负载测试..."
        
        # 检查API服务是否运行
        if nc -z localhost 8000; then
            locust -f tests/performance/locustfile.py \
                --host=http://localhost:8000 \
                --users=50 \
                --spawn-rate=5 \
                --run-time=60s \
                --headless \
                --html=tests/reports/locust_report.html \
                --csv=tests/reports/locust_stats
        else
            log_warning "API服务未运行，跳过Locust测试"
        fi
    fi
    
    log_success "性能测试完成"
}

# 运行安全测试
run_security_tests() {
    log_info "运行安全测试..."
    
    # Bandit安全扫描
    if command -v bandit &> /dev/null; then
        log_info "运行Bandit安全扫描..."
        bandit -r src/ -f json -o tests/reports/bandit_report.json || log_warning "发现安全问题"
    fi
    
    # Safety依赖扫描
    if command -v safety &> /dev/null; then
        log_info "运行Safety依赖扫描..."
        safety check --json --output tests/reports/safety_report.json || log_warning "发现依赖安全问题"
    fi
    
    # Semgrep代码扫描
    if command -v semgrep &> /dev/null; then
        log_info "运行Semgrep代码扫描..."
        semgrep --config=auto src/ --json --output=tests/reports/semgrep_report.json || log_warning "发现代码安全问题"
    fi
    
    # 运行安全测试用例
    pytest tests/security/ \
        $VERBOSE \
        $PATTERN \
        $MARKERS \
        --junit-xml=tests/reports/security_test_results.xml \
        --timeout=120
    
    log_success "安全测试完成"
}

# 生成测试报告
generate_test_report() {
    log_info "生成测试报告..."
    
    # 合并测试结果
    if command -v pytest &> /dev/null; then
        # 生成综合覆盖率报告
        if [ -f ".coverage" ]; then
            coverage combine
            coverage report
            coverage html -d tests/reports/coverage_html
        fi
    fi
    
    # 生成Allure报告
    if command -v allure &> /dev/null && [ -d "tests/reports/allure-results" ]; then
        allure generate tests/reports/allure-results -o tests/reports/allure-report --clean
        log_info "Allure报告生成完成: tests/reports/allure-report/index.html"
    fi
    
    # 生成测试总结
    cat > tests/reports/test_summary.txt << EOF
测试执行总结
===========

执行时间: $(date)
测试类型: $TEST_TYPE
Python版本: $(python3 --version)

报告文件:
- HTML测试报告: tests/reports/test_report.html
- 覆盖率报告: tests/reports/coverage_html/index.html
- 性能测试报告: tests/reports/locust_report.html
- 安全扫描报告: tests/reports/bandit_report.json

测试状态: 完成
EOF
    
    log_success "测试报告生成完成"
}

# 主执行逻辑
main() {
    log_info "开始执行测试脚本..."
    log_info "测试类型: $TEST_TYPE"
    
    # 仅设置环境
    if [ "$SETUP_ONLY" = "true" ]; then
        check_python_env
        install_test_dependencies
        setup_test_environment
        exit 0
    fi
    
    # 仅清理环境
    if [ "$CLEANUP_ONLY" = "true" ]; then
        cleanup_test_environment
        exit 0
    fi
    
    # 检查环境
    check_python_env
    install_test_dependencies
    
    # 设置测试环境
    setup_test_environment
    
    # 运行代码质量检查
    run_code_quality_checks
    
    # 根据测试类型执行相应测试
    case $TEST_TYPE in
        "unit")
            run_unit_tests
            ;;
        "integration")
            run_integration_tests
            ;;
        "e2e")
            run_e2e_tests
            ;;
        "performance")
            run_performance_tests
            ;;
        "security")
            run_security_tests
            ;;
        "quick")
            run_unit_tests
            ;;
        "all")
            run_unit_tests
            run_integration_tests
            run_e2e_tests
            run_performance_tests
            run_security_tests
            ;;
        *)
            log_error "未知的测试类型: $TEST_TYPE"
            show_help
            exit 1
            ;;
    esac
    
    # 生成测试报告
    generate_test_report
    
    # 清理测试环境
    cleanup_test_environment
    
    log_success "所有测试执行完成！"
    log_info "查看测试报告: tests/reports/"
}

# 信号处理
trap 'log_warning "测试被中断"; cleanup_test_environment; exit 1' INT TERM

# 执行主函数
main "$@" 